//! 资源注册表
//!
//! 管理所有可用资源的元数据

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::{Path, PathBuf};

/// 资源元数据
///
/// 描述资源的基本信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceMetadata {
    /// 资源键（唯一标识符）
    pub key: String,

    /// 资源代码（如地区代码）
    pub code: String,

    /// 资源名称
    pub name: String,

    /// 资源路径
    pub path: PathBuf,

    /// 资源维度
    pub dimensions: HashMap<String, String>,

    /// 创建时间
    pub created_at: chrono::DateTime<chrono::Utc>,

    /// 更新时间
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

/// 资源注册表
///
/// 管理所有可用资源的元数据
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceRegistry {
    /// 资源映射表 (key -> metadata)
    pub resources: HashMap<String, ResourceMetadata>,
}

impl ResourceRegistry {
    /// 创建新的资源注册表
    pub fn new() -> Self {
        Self { resources: HashMap::new() }
    }

    /// 从文件加载注册表
    pub fn load_from_file(path: impl AsRef<Path>) -> anyhow::Result<Self> {
        let content = std::fs::read_to_string(path)?;
        let registry = serde_json::from_str(&content)?;
        Ok(registry)
    }

    /// 保存注册表到文件
    pub fn save_to_file(
        &self,
        path: impl AsRef<Path>,
    ) -> anyhow::Result<()> {
        let content = serde_json::to_string_pretty(self)?;
        std::fs::write(path, content)?;
        Ok(())
    }

    /// 注册资源
    pub fn register(
        &mut self,
        metadata: ResourceMetadata,
    ) {
        self.resources.insert(metadata.key.clone(), metadata);
    }

    /// 注销资源
    pub fn unregister(
        &mut self,
        key: &str,
    ) -> Option<ResourceMetadata> {
        self.resources.remove(key)
    }

    /// 获取资源元数据
    pub fn get(
        &self,
        key: &str,
    ) -> Option<&ResourceMetadata> {
        self.resources.get(key)
    }

    /// 检查资源是否存在
    pub fn exists(
        &self,
        key: &str,
    ) -> bool {
        self.resources.contains_key(key)
    }

    /// 获取所有资源键
    pub fn list_all_keys(&self) -> Vec<String> {
        self.resources.keys().cloned().collect()
    }

    /// 获取指定代码的所有资源
    pub fn get_resources_for_code(
        &self,
        code: &str,
    ) -> Vec<&ResourceMetadata> {
        self.resources.values().filter(|m| m.code == code).collect()
    }

    /// 获取指定维度的所有资源
    pub fn get_resources_by_dimension(
        &self,
        dim_key: &str,
        dim_value: &str,
    ) -> Vec<&ResourceMetadata> {
        self.resources.values().filter(|m| m.dimensions.get(dim_key) == Some(&dim_value.to_string())).collect()
    }

    /// 获取资源数量
    pub fn count(&self) -> usize {
        self.resources.len()
    }
}

impl Default for ResourceRegistry {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_registry_basic() {
        let mut registry = ResourceRegistry::new();

        let metadata = ResourceMetadata {
            key: "test_key".to_string(),
            code: "610100".to_string(),
            name: "西安市".to_string(),
            path: PathBuf::from("/data/test.db"),
            dimensions: HashMap::from([("year".to_string(), "2022".to_string())]),
            created_at: chrono::Utc::now(),
            updated_at: chrono::Utc::now(),
        };

        registry.register(metadata.clone());

        assert!(registry.exists("test_key"));
        assert_eq!(registry.get("test_key").unwrap().code, "610100");
    }

    #[test]
    fn test_registry_filter() {
        let mut registry = ResourceRegistry::new();

        let metadata1 = ResourceMetadata {
            key: "key1".to_string(),
            code: "610100".to_string(),
            name: "西安市".to_string(),
            path: PathBuf::from("/data/test1.db"),
            dimensions: HashMap::from([("year".to_string(), "2022".to_string())]),
            created_at: chrono::Utc::now(),
            updated_at: chrono::Utc::now(),
        };

        let metadata2 = ResourceMetadata {
            key: "key2".to_string(),
            code: "610100".to_string(),
            name: "西安市".to_string(),
            path: PathBuf::from("/data/test2.db"),
            dimensions: HashMap::from([("year".to_string(), "2023".to_string())]),
            created_at: chrono::Utc::now(),
            updated_at: chrono::Utc::now(),
        };

        registry.register(metadata1);
        registry.register(metadata2);

        let resources_2022 = registry.get_resources_by_dimension("year", "2022");
        assert_eq!(resources_2022.len(), 1);
        assert_eq!(resources_2022[0].key, "key1");
    }
}
